package com.naiterui.ehp.bs.b2c.address.service.impl;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bs.b2c.address.constants.AddrConstants;
import com.naiterui.ehp.bs.b2c.address.entity.City;
import com.naiterui.ehp.bs.b2c.address.exception.AddrExceptionCodes;
import com.naiterui.ehp.bs.b2c.address.repository.CityRepository;
import com.naiterui.ehp.bs.b2c.address.service.ICityService;
import com.naiterui.ehp.bs.b2c.address.vo.CityVO;
import com.naiterui.ehp.bs.b2c.common.bo.address.CityBO;
import com.naiterui.ehp.bs.b2c.constants.MallConstants;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CityServiceImpl implements ICityService {

    @Autowired
    private CityRepository cityRepository;

    private static final String CITY_CACHE_KEY = MallConstants.RDS_KEY_PRE_SALE_ADDR + "city_cache";

    private static final Integer CACHE_TIME_SEC = 60 * 60 * 24;

    /**
     * 城市类型-区层级深度
     */
    private static final Integer CITY_TYPE_COUNTRY_DEPTH = 3;

    @Override
    public List<CityVO> getAll() {

        // 获取缓存
        List<CityVO> cityCache = this.getRedisCity();
        if (cityCache != null) {
            log.info("从缓存获取城市是列表");
            this.addVirtualCity(cityCache);
            return cityCache;
        }

        List<City> cityList = this.cityRepository.findAllByAvailable(CommonConstant.AVAILABLE_TRUE);
        Map<Long, List<City>> cityParentMap = cityList.stream().collect(Collectors.groupingBy(City::getParentId));

        // 获取以市级城市上级ID为K的Map(过滤市级城市，并组装下级城市列表后按上级城市ID为K分组)
        Map<Long, List<CityVO>> cityVOMap = cityList
                // 过滤市级行政区划城市(倒数第二级城市区划)
                .stream().filter(c -> AddrConstants.CITY_TYPE_CITY.equals(c.getType()))
                .map(c -> CityVO.builder()
                                .id(c.getId())
                                .name(c.getName())
                                .parentId(c.getParentId())
                                .childs(
                                        // 将区级节点置入(倒数第一级行政区划)
                                        this.transferCity2VO(cityParentMap.get(c.getId()))).build()
                ).collect(Collectors.groupingBy(CityVO::getParentId));

        // 获取省级行政区划(顶级节点)
        List<CityVO> cityVOList = cityList.stream().filter(c -> AddrConstants.CITY_TYPE_PROVINCE.equals(c.getType()))
                                          .map(c -> CityVO.builder()
                                                          .id(c.getId())
                                                          .name(c.getName())
                                                          .parentId(c.getParentId())
                                                          .childs(cityVOMap.get(c.getId()))
                                                          .build())
                                          .collect(Collectors.toList());
        // 设置城市缓存
        this.setRedisCity(cityVOList);

        this.addVirtualCity(cityVOList);
        return cityVOList;
    }

    @Override
    public CityBO getCityById(Long cityId) throws BusinessException {
        Optional<City> city = this.cityRepository.findById(cityId);
        if (!city.isPresent()) {
            log.warn("城市ID无效 {}", cityId);
            throw new BusinessException(AddrExceptionCodes.CITY_ID_INVLID);
        }
        String[] parentNameArr = city.get().getParentName().split(",");
        if (!AddrConstants.CITY_TYPE_COUNTRY.equals(city.get().getType()) || CITY_TYPE_COUNTRY_DEPTH > parentNameArr.length) {
            throw new BusinessException(AddrExceptionCodes.CITY_TYPE_ERROR);
        }
        CityBO cityBO = new CityBO();
        cityBO.setProvice(parentNameArr[1]);
        cityBO.setCity(parentNameArr[2]);
        cityBO.setCountry(city.get().getName());
        return cityBO;
    }

    private List<CityVO> transferCity2VO(List<City> cityList) {
        if (cityList == null) {
            return null;
        }
        return cityList.stream()
                       .map(c -> CityVO.builder().id(c.getId()).name(c.getName()).parentId(c.getParentId()).build())
                       .collect(Collectors.toList());
    }

    /**
     * 获取城市缓存
     *
     * @return
     */
    private List<CityVO> getRedisCity() {
        List<CityVO> cityVOList = null;
        try {
            cityVOList = (List<CityVO>) RedisUtil.valueOps().getObject(CITY_CACHE_KEY);
        } catch (Exception e) {
            log.error("获取城市缓存异常", e);
        }
        return cityVOList;
    }

    /**
     * 设置城市缓存
     *
     * @param cityVOList
     */
    private void setRedisCity(List<CityVO> cityVOList) {
        try {
            RedisUtil.valueOps().set(CITY_CACHE_KEY, cityVOList, CACHE_TIME_SEC);
        } catch (Exception e) {
            log.error("设置城市缓存异常", e);
        }
    }


    /**
     * 补全第三级城市(用二级城市填充)
     *
     * @param cityVOList
     */
    private void addVirtualCity(List<CityVO> cityVOList) {
        cityVOList.forEach(p -> p.getChilds().forEach(c -> {
            if (c.getChilds() == null || c.getChilds().isEmpty()) {
                List<CityVO> virtualCity = Lists.newArrayList();
                CityVO cityVO = CityVO.builder().id(c.getId()).name(c.getName()).parentId(c.getParentId()).build();
                virtualCity.add(cityVO);
                c.setChilds(virtualCity);
            }
        }));
    }
}
